package com.ruyiadmin.springboot.common.core.system.entities;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.ruyiadmin.springboot.common.core.system.entities.base.BaseDomain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import java.util.List;
import java.util.regex.Pattern;

/**
 * <p>
 * 系统查询条件类
 * </p>
 *
 * @author RuYiAdmin
 * @since 2022-07-15
 */
@AllArgsConstructor
@NoArgsConstructor
@Data
public class QueryCondition extends BaseDomain {
    //起始页
    @JsonProperty(value = "PageIndex")
    private int pageIndex;
    //分页大小
    @JsonProperty(value = "PageSize")
    private int pageSize;
    //排序字段
    @JsonProperty(value = "Sort")
    private String sort;
    //查询条件
    @JsonProperty(value = "QueryItems")
    private List<QueryItem> queryItems;

    //region 获取查询条件

    /**
     * 获取查询条件
     *
     * @param wrapper QueryWrapper对象
     */
    public <T> void getQueryWrapper(QueryWrapper<T> wrapper) {
        this.convertToQueryWrapper(wrapper);
        this.convertOrder(wrapper);
        //MyBatisPlus分页按当前页编号
        this.pageIndex = this.pageIndex + 1;
    }

    //endregion

    //region 转化查询条件

    /**
     * 转化查询条件
     *
     * @param wrapper QueryWrapper对象
     */
    public <T> void convertToQueryWrapper(QueryWrapper<T> wrapper) {
        List<QueryItem> queryItems = this.getQueryItems();
        if (queryItems != null && queryItems.size() > 0) {
            for (QueryItem queryItem : this.getQueryItems()) {
                switch (queryItem.getQueryMethod()) {
                    case Equal:
                        wrapper = wrapper.eq(queryItem.getField(), queryItem.getValue());
                        break;
                    case Like:
                        wrapper = wrapper.like(queryItem.getField(), queryItem.getValue());
                        break;
                    case LessThan:
                        wrapper = wrapper.lt(queryItem.getField(), queryItem.getValue());
                        break;
                    case LessThanOrEqual:
                        wrapper = wrapper.le(queryItem.getField(), queryItem.getValue());
                        break;
                    case GreaterThan:
                        wrapper = wrapper.gt(queryItem.getField(), queryItem.getValue());
                        break;
                    case GreaterThanOrEqual:
                        wrapper = wrapper.ge(queryItem.getField(), queryItem.getValue());
                        break;
                    case BetweenAnd:
                        Object[] array = queryItem.getValue().toString().split(",");
                        wrapper = wrapper.between(queryItem.getField(), array[0], array[1]);
                        break;
                    case Include:
                        wrapper = wrapper.in(queryItem.getField(), queryItem.getValue());
                        break;
                    case OrLike:
                        wrapper = wrapper.or().like(queryItem.getField(), queryItem.getValue());
                        break;
                    case NotEqual:
                        wrapper = wrapper.ne(queryItem.getField(), queryItem.getValue());
                        break;
                    default:
                        break;
                }
            }
        }
    }

    //endregion

    //region 数据列表排序

    /**
     * 排序
     *
     * @param wrapper QueryWrapper对象
     */
    public <T> void convertOrder(QueryWrapper<T> wrapper) {
        if (StringUtils.isNotBlank(this.getSort())) {
            String column, direction;
            String[] array;
            String[] orders = this.getSort().split(",");
            for (String sort : orders) {
                array = sort.split(" ");
                column = array[0];
                direction = array[1];
                if (StringUtils.isNotBlank(direction)) {
                    if (direction.equalsIgnoreCase("ASC")) {
                        wrapper = wrapper.orderByAsc(column);
                    } else if (direction.equalsIgnoreCase("DESC")) {
                        wrapper = wrapper.orderByDesc(column);
                    }
                }
            }
        }
    }

    //endregion

    //region 转化为Mongo查询条件

    public Query toCriteriaQuery() {

        Query query = new Query();

        //region 转化查询条件

        List<QueryItem> queryItems = this.getQueryItems();
        if (queryItems != null && queryItems.size() > 0) {
            for (QueryItem queryItem : this.getQueryItems()) {
                switch (queryItem.getQueryMethod()) {
                    case Equal:
                        query.addCriteria(Criteria.where(queryItem.getField()).is(queryItem.getValue()));
                        break;
                    case Like:
                        Pattern pattern = Pattern.compile("^.*" + queryItem.getValue() + ".*$", Pattern.CASE_INSENSITIVE);
                        query.addCriteria(Criteria.where(queryItem.getField()).regex(pattern));
                        break;
                    case LessThan:
                        query.addCriteria(Criteria.where(queryItem.getField()).lt(queryItem.getValue()));
                        break;
                    case LessThanOrEqual:
                        query.addCriteria(Criteria.where(queryItem.getField()).lte(queryItem.getValue()));
                        break;
                    case GreaterThan:
                        query.addCriteria(Criteria.where(queryItem.getField()).gt(queryItem.getValue()));
                        break;
                    case GreaterThanOrEqual:
                        query.addCriteria(Criteria.where(queryItem.getField()).gte(queryItem.getValue()));
                        break;
                    case BetweenAnd:
                        Object[] array = queryItem.getValue().toString().split(",");
                        query.addCriteria(Criteria.where(queryItem.getField()).gte(array[0]));
                        query.addCriteria(Criteria.where(queryItem.getField()).lte(array[1]));
                        break;
                    case Include:
                        query.addCriteria(Criteria.where(queryItem.getField()).in(queryItem.getValue()));
                        break;
                    case OrLike:
                        Pattern patternOr = Pattern.compile("^.*" + queryItem.getValue() + ".*$", Pattern.CASE_INSENSITIVE);
                        query.addCriteria(new Criteria().orOperator(Criteria.where(queryItem.getField()).regex(patternOr)));
                        break;
                    case NotEqual:
                        query.addCriteria(Criteria.where(queryItem.getField()).ne(queryItem.getValue()));
                        break;
                    default:
                        break;
                }
            }
        }

        //endregion

        //region 转化排序条件

        if (StringUtils.isNotBlank(this.getSort())) {
            String column, direction;
            String[] array;
            String[] orders = this.getSort().split(",");
            for (String sort : orders) {
                array = sort.split(" ");
                column = array[0];
                direction = array[1];
                if (StringUtils.isNotBlank(direction)) {
                    if (direction.equalsIgnoreCase("ASC")) {
                        query.with(Sort.by(Sort.Order.asc(column)));
                    } else if (direction.equalsIgnoreCase("DESC")) {
                        query.with(Sort.by(Sort.Order.desc(column)));
                    }
                }
            }
        }

        //endregion

        return query;
    }

    //endregion

    //region 转化为ES查询条件

    public NativeSearchQuery toNativeSearchQuery() {
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

        //region 转化查询条件

        List<QueryItem> queryItems = this.getQueryItems();
        if (queryItems != null && queryItems.size() > 0) {
            for (QueryItem queryItem : this.getQueryItems()) {
                switch (queryItem.getQueryMethod()) {
                    case Equal:
                        queryBuilder.withQuery(QueryBuilders
                                .termQuery(queryItem.getField(), queryItem.getValue()));
                        break;
                    case Like:
                        queryBuilder.withQuery(QueryBuilders
                                .wildcardQuery(queryItem.getField(), "*" + queryItem.getValue() + "*"));
                        break;
                    case LessThan:
                        queryBuilder.withQuery(QueryBuilders
                                .rangeQuery(queryItem.getField()).lt(queryItem.getValue()));
                        break;
                    case LessThanOrEqual:
                        queryBuilder.withQuery(QueryBuilders
                                .rangeQuery(queryItem.getField()).lte(queryItem.getValue()));
                        break;
                    case GreaterThan:
                        queryBuilder.withQuery(QueryBuilders
                                .rangeQuery(queryItem.getField()).gt(queryItem.getValue()));
                        break;
                    case GreaterThanOrEqual:
                        queryBuilder.withQuery(QueryBuilders
                                .rangeQuery(queryItem.getField()).gte(queryItem.getValue()));
                        break;
                    case BetweenAnd:
                        Object[] array = queryItem.getValue().toString().split(",");
                        queryBuilder.withQuery(QueryBuilders
                                .rangeQuery(queryItem.getField())
                                .from(array[0]).to(array[1])
                                .includeLower(true) // 包含上界
                                .includeUpper(true) // 包含下界
                        );
                        break;
                    case Include:
                        queryBuilder.withQuery(QueryBuilders.termQuery(
                                queryItem.getField(),
                                queryItem.getValue().toString().split(",")));
                        break;
                    case OrLike:
                        queryBuilder.withQuery(QueryBuilders.boolQuery().should(
                                QueryBuilders.termQuery(queryItem.getField(), queryItem.getValue())));
                        break;
                    case NotEqual:
                        queryBuilder.withQuery(QueryBuilders.boolQuery().mustNot(
                                QueryBuilders.termQuery(queryItem.getField(), queryItem.getValue())));
                        break;
                    default:
                        break;
                }
            }
        }

        //endregion

        //region 转化排序条件

        if (StringUtils.isNotBlank(this.getSort())) {
            String column, direction;
            String[] array;
            String[] orders = this.getSort().split(",");
            for (String sort : orders) {
                array = sort.split(" ");
                column = array[0];
                direction = array[1];
                if (StringUtils.isNotBlank(direction)) {
                    if (direction.equalsIgnoreCase("ASC")) {
                        queryBuilder.withSort(SortBuilders.fieldSort(column).order(SortOrder.ASC));
                    } else if (direction.equalsIgnoreCase("DESC")) {
                        queryBuilder.withSort(SortBuilders.fieldSort(column).order(SortOrder.DESC));
                    }
                }
            }
        }

        //endregion

        //分页
        queryBuilder.withPageable(PageRequest.of(this.getPageIndex(), this.getPageSize()));

        return queryBuilder.build();
    }

    //endregion

}
